﻿#include <GUIConstantsEx.au3>
#include <Constants.au3>

Opt("MustDeclareVars",1)

Global $size = 5		;;最大支持设备数
Global $startInterval = 200000 ;;毫秒，每个设备每次启动脚本的间隔
;; [设备编号][pid][设备全部信息][设备启动参数][设备启动时间][设备启动参数价格fromto],,...;
Global $pidList[$size][6]	
Global $adbDir = @WorkingDir & "\resources\adb"
Global $rootDir = "D:\AirtestWorkSpace\fuyuanwaiUItest\"
Global $airTestLog_root = "http://123.60.96.211:1955//airTestLog/"
Global $static_root = "http://123.60.96.211:1955//airTestLog/static"
Global $export = "D:\javaWorkSpace\testServerNode\web\airTestLog\"
;;不知道为什么全局数组在方法中放入参数后，后来发现是n2这个参数在没有回调后出发了清空参数的方法
Global $readDevice
Global $readTestFiles
Global $today = @YEAR & "-" & @MON & "-" & @MDAY
;;日志table的日期列表和默认展示日期
Global $dateList, $defDate
;;节点服务器中日期目录下的日志列表
Global $htmlLoglist

Dim $test

ShowList()


;通过adb device获取链接的设备
Func GetList()
	Local $sOutput,$line,$lines
	$sOutput = Run(@ComSpec & " /c "&$adbDir&" devices -l", @SystemDir, @SW_HIDE, $STDOUT_CHILD)
	
	While 1
		$line = StdoutRead($sOutput)
		If @error Then ExitLoop
		$lines &= $line
	Wend
	Local $aArray = StringSplit(StringTrimRight(StringStripCR($lines), StringLen(@LF)), @LF)
	Local $returnStr
	For $i = 2 To $aArray[0]
		If $i = 0 OR $i = $aArray[0] Then ExitLoop
		$readDevice = $readDevice & "|" & getDevicePid($aArray[$i])
		$returnStr = $returnStr & $aArray[$i] & "|"
	Next
	$returnStr = StringTrimRight($returnStr, 1)
	Return $returnStr
EndFunc


;;加载gui, 并检查pid是否存在
Func ShowList()
	init()
	Local $menu1, $nDevices, $n2, $nRunTest, $n4, $nTestFiles, $n6, $n7, $n8, $msg, $menustate, $menutext, $ns, $ne
	Local $runAllTest, $genLogBut, $logList, $choseLog, $choseData
	Local $showErr, $clearErr, $clearAll
	Local $devList = GetList()
	Local $testFiles = gettestFile()
	findLogDirs()
	loadDefDateLog()
	
	
	GUICreate("APP自动化测试助手",850) ; 创建一个居中显示的 GUI 窗口
	
	GUICtrlCreateTab(10, 10, 833, 380)

    GUICtrlCreateTabItem("测试用例")
	;$menu1 = GUICtrlCreateMenu("设备列表")
	$nDevices = GUICtrlCreateList("", 10, 30, 600, 200)
	GUICtrlSetData($nDevices, $devList, "item2")
	$nTestFiles = GUICtrlCreateList("", 620, 30, 220, 200)
	GUICtrlSetData($nTestFiles, $testFiles, "item3")
	;亮屏
	$ns = GUICtrlCreateButton("亮屏", 15, 235, 50)
	GUICtrlSetOnEvent($ns, "")
	;熄屏
	$ne = GUICtrlCreateButton("熄屏", 75, 235, 50)
	GUICtrlSetOnEvent($ne, "")
	$nRunTest = GUICtrlCreateButton("执行", 135, 235, 50)
	GUICtrlSetState(-1, $GUI_FOCUS)
	$n4 = GUICtrlCreateButton("停止", 195, 235, 50)
	GUICtrlSetState(-1, $GUI_FOCUS)
	$n6 = GUICtrlCreateButton("刷新", 255, 235, 50)
	GUICtrlSetState($n6, $GUI_FOCUS)
	$runAllTest = GUICtrlCreateButton("执行全部", 315, 235, 80)
	GUICtrlSetState($runAllTest, $GUI_FOCUS)
	$genLogBut = GUICtrlCreateButton("生成日志", 405, 235, 80)
	GUICtrlSetState($genLogBut, $GUI_FOCUS)
	
	GUICtrlCreateTabItem("展示日志")
	$choseData = GUICtrlCreateCombo("", 15, 37, 100)
    GUICtrlSetData($choseData, $dateList, $defDate)
	$choseLog = GUICtrlCreateList("", 15, 70, 220, 200)
	GUICtrlSetData($choseLog, $htmlLoglist, "item4")
	$showErr = GUICtrlCreateButton("标识失败", 135, 35, 80)
	GUICtrlSetState($showErr, $GUI_FOCUS)
	$clearErr = GUICtrlCreateButton("清空失败", 235, 35, 80)
	GUICtrlSetState($clearErr, $GUI_FOCUS)
	$clearAll = GUICtrlCreateButton("清空所有", 335, 35, 80)
	GUICtrlSetState($clearAll, $GUI_FOCUS)
	
	
	GUISetState(@SW_SHOW) ; 显示一个空白的窗口
	; 运行界面,直到窗口被关闭 
	Do
		$msg = GUIGetMsg()
		;(展示日志)tab中的方法
		If $msg = $choseLog Then
			openChrome($choseData, $choseLog)
		EndIf
		
		;(测试用例)tab中的方法
		;读取选中设备
		If $msg = $nDevices Then
			$readDevice = getDevicePid(GUICtrlRead($nDevices)) 
		EndIf
		
		;读取选中测试脚本名
		If $msg = $nTestFiles Then
			$readTestFiles = GUICtrlRead($nTestFiles)
		EndIf
		
		;点亮屏幕
		If $msg = $ns Then
			;MsgBox(4096, "全部执行", $readDevice)
			Dim $readDeviceArr = StringSplit($readDevice, "|")
			;For $oneDevice In $readDeviceArr
			For $i=2 To $readDeviceArr[0] Step +1
				Dim $comm1 = $adbDir & " -s " & $readDeviceArr[$i] & " shell input keyevent 3"
				Run(@ComSpec & " /c "&$comm1, @SystemDir, @SW_HIDE, $STDOUT_CHILD)
			Next
		EndIf
		
		;熄屏幕
		If $msg = $ne Then
			Dim $readDeviceArr = StringSplit($readDevice, "|")
			;For $oneDevice In $readDeviceArr
			For $i=2 To $readDeviceArr[0] Step +1
				Dim $comm1 = $adbDir & " -s " & $readDeviceArr[$i] & " shell input keyevent 26"
				Run(@ComSpec & " /c "&$comm1, @SystemDir, @SW_HIDE, $STDOUT_CHILD)
			Next
		EndIf
		
		;点运行
		If $msg = $nRunTest Then
			startDevice($readDevice, $readTestFiles)
		EndIf
		
		
		;刷新
		If $msg = $n6 Then
			$readDevice = ""
			GUICtrlSetData($nDevices, "")
			GUICtrlSetData($nDevices, GetList(), "item2")
			GUICtrlSetData($nTestFiles, "")
			GUICtrlSetData($nTestFiles, gettestFile(), "item3")
			$htmlLoglist = ""
			GUICtrlSetData($choseLog, "", "item4")
			loadDefDateLog()
			GUICtrlSetData($choseLog, $htmlLoglist, "item4")
		EndIf
		
		;全部执行
		If $msg = $runAllTest Then
			startAllTest2AllDevice()
		EndIf
		
		;生成日志
		If $msg = $genLogBut Then
			genLog()
		EndIf
		
		;;标记错误日志
		If $msg = $showErr Then 
			;MsgBox(4096, "showErr", "showErr")
			$htmlLoglist = ""
			markErrLog()
			GUICtrlSetData($choseLog, "", "item4")
			GUICtrlSetData($choseLog, $htmlLoglist, "item4")
		EndIf
		
		;;清空错误日志
		If $msg = $clearErr Then 
			;MsgBox(4096, "clearErr", "clearErr")
			$htmlLoglist = ""
			removeErrLog()
			GUICtrlSetData($choseLog, "", "item4")
			loadDefDateLog()
			GUICtrlSetData($choseLog, $htmlLoglist, "item4")
		EndIf
		
		;;清空所有日志
		If $msg = $clearAll Then 
			;MsgBox(4096, "clearErr", "clearErr")
			$htmlLoglist = ""
			removeAllLog()
			GUICtrlSetData($choseLog, "", "item4")
			loadDefDateLog()
			GUICtrlSetData($choseLog, $htmlLoglist, "item4")
		EndIf
		
		
	Until $msg = $GUI_EVENT_CLOSE
EndFunc   ;==>Example

Func openChrome($choseData, $choseLog)
	;MsgBox(4096, "选择了", GUICtrlRead($choseLog))
	Dim $nowChoseData = GUICtrlRead($choseData)
	Dim $nowChoseLog = GUICtrlRead($choseLog)
	;start chrome www.baidu.com
	Dim $openUrl = "start chrome " & $airTestLog_root & $nowChoseData & "/" & $nowChoseLog & "/log.html"
	Run(@ComSpec & " /c "&$openUrl, @SystemDir, @SW_HIDE, $STDOUT_CHILD)	
EndFunc

Func removeAllLog()
	;移除所有的日志
	Local $hSearch = FileFindFirstFile($export & $defDate & "\*.log")

	; 检查搜索是否成功
	If $hSearch = -1 Then
		MsgBox(4096, "loadDefDateLog错误", "没有文件/目录 匹配搜索")
		Exit
	EndIf

	While 1
	;先移除所有[X] 目录  ;DirRemove($sFldr1, 1)
		Local $sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		DirRemove($export & $defDate & "\" & $sFile, 1)
	WEnd
	
	; 关闭搜索句柄
	FileClose($hSearch)

EndFunc

Func removeErrLog()
	;移除错误的日志
	Local $hSearch = FileFindFirstFile($export & $defDate & "\*.log")

	; 检查搜索是否成功
	If $hSearch = -1 Then
		MsgBox(4096, "loadDefDateLog错误", "没有文件/目录 匹配搜索")
		Exit
	EndIf

	While 1
	;先移除所有[X] 目录  ;DirRemove($sFldr1, 1)
		Local $sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		If StringInStr($sFile, "[X]") <> 0 Then 
			;MsgBox(4096, "DirRemove", $export & $defDate & "\" & $sFile)
			DirRemove($export & $defDate & "\" & $sFile, 1)
			ContinueLoop
		EndIf
	WEnd
	
	; 关闭搜索句柄
	FileClose($hSearch)

EndFunc

Func markErrLog()
	;刷新日志列表，标记出出错的日志
	Local $hSearch = FileFindFirstFile($export & $defDate & "\*.log")

	; 检查搜索是否成功
	If $hSearch = -1 Then
		MsgBox(4096, "loadDefDateLog错误", "没有文件/目录 匹配搜索")
		Exit
	EndIf
	
	While 1
		Local $sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		$sFile = findErrLog($sFile) & $sFile
		$htmlLoglist = $htmlLoglist & $sFile & "|"
	WEnd
	
	; 关闭搜索句柄
	FileClose($hSearch)

EndFunc

Func loadDefDateLog()
	;从$defDate加载默认日期的测试日志
	Local $hSearch = FileFindFirstFile($export & $defDate & "\*.log")

	; 检查搜索是否成功
	If $hSearch = -1 Then
		MsgBox(4096, "loadDefDateLog错误", "没有文件/目录 匹配搜索")
		Return ""
	EndIf
	
	While 1
		Local $sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		$htmlLoglist = $htmlLoglist & $sFile & "|"
	WEnd
	
	; 关闭搜索句柄
	FileClose($hSearch)
EndFunc

Func findErrLog($logFileName)
	;;为loadDefDateLog方法找到日志中的traceback关键字，以此判断测试可能出错了
	Local $file = FileOpen($export & $defDate & "\" & $logFileName & "\log\log.txt", 0)

	; 检查打开的文件是否可读
	If $file = -1 Then
		MsgBox(4096, "findErrLog", "不能打开文件.")
		Exit
	EndIf
	
	; 每次读取一行文本,直到文件结束.
	While 1
		Local $line = FileReadLine($file)
		If @error = -1 Then ExitLoop
		If StringInStr($line, "traceback") <> 0 AND (StringInStr($line, "assert_exists") <> 0 OR StringInStr($line, "touch") <> 0) Then
			;MsgBox(4096, "错误1", $line & " -- " & $export & $defDate & "\" & $logFileName & "\log\log.txt")
			;;判断$logFileName是否带有错误标记[X]
			If StringInStr($logFileName, "[X]") = 0 Then
				;MsgBox(4096, "错误2", $export & $defDate & "\" & "[X]" & $logFileName)
				Dim $res = DirCopy($export & $defDate & "\" & $logFileName, $export & $defDate & "\" & "[X]" & $logFileName, 0)
				;MsgBox(4096, "DirCopy", $res)
				DirRemove($export & $defDate & "\" & $logFileName, 1)
				Return "[X]"
			EndIf
			Return ""
		EndIf
	WEnd
	Return ""
EndFunc

Func findLogDirs()
	;;从节点服务器中获取.air目录下的所有日期目录
	Local $hSearch = FileFindFirstFile($export & "*-*-*")
	Local $testFiles

	; 检查搜索是否成功
	If $hSearch = -1 Then
		MsgBox(4096, "findLogDirs", "没有文件/目录 匹配搜索")
		Exit
	EndIf

	While 1
		Local $sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		If $sFile == "static" Then ContinueLoop
		$defDate = $sFile
		$testFiles = $testFiles & $sFile & "|"
		
	WEnd
	
	; 关闭搜索句柄
	FileClose($hSearch)
	$dateList = $testFiles
	
EndFunc

Func genLog()
	;;执行了测试用例在logList文件中写入logPic/日期/目录下的 文件名（FKsceneYijianjiayou_11748585）
	;;按了“展示日志”按钮后读取logList中的数据，用report命令生成html日志
	;;airtest report E:\AirtestWorkSpace\fuyuanwaiUItest\FYWsceneShoujichongzhi.air --log_root E:\AirtestWorkSpace\fuyuanwaiUItest\logPic\FYWsceneShoujichongzhi_11748585 --lang zh --export D:\javaWorkSpace\testServerNode\web\airTestLog --static_root http://localhost:1988/airTestLog/static
	Local $file = FileOpen("logList", 0)
	; 检查打开的文件是否可为读
	If $file = -1 Then
		MsgBox(4096, "genLog", "不能打开文件.")
		Exit
	EndIf
	
	While 1
		Dim $line = FileReadLine($file)
		if $line == "" Then ExitLoop
		
		Dim $s1 = StringSplit($line, "_")
		Dim $data = $s1[1]
		Dim $airFileName = $s1[2] & ".air"
		Dim $deviceName = $s1[3]
		;MsgBox(4096, "airFileName", $data & "__"&$airFileName& "__"&$deviceName)
		Dim $genReportComm = "python -m airtest report " & $rootDir & $airFileName 
		$genReportComm = $genReportComm & " --log_root " & $rootDir & "logPic\" & $data & "\" & $s1[2] & "_" & $deviceName
		$genReportComm = $genReportComm & " --lang zh --export " & $export & $data & " --static_root " & $static_root
		;MsgBox(4096, "genReportComm", $genReportComm)
		
		Run(@ComSpec & " /c "&$genReportComm, @SystemDir, @SW_HIDE, $STDOUT_CHILD)
		Sleep(1000)
	WEnd
	MsgBox(4096, "genLog", "html日志生成完毕")
	;;日志写完了 ,logList文件清空
	Local $file = FileOpen("logList", 2)
	If $file = -1 Then
		MsgBox(4096, "genLog", "不能打开文件logList")
		Exit
	EndIf
	FileWrite($file, "")
	FileClose($file)

EndFunc

Func save2LogList($testFile)
	;;执行了测试用例在logList文件中写入logPic/日期/目录下的 文件名（FKsceneYijianjiayou_11748585）
	Local $file = FileOpen("logList", 1)
	If $file = -1 Then
		MsgBox(4096, "save2LogList", "不能打开文件.")
		Exit
	EndIf
	;MsgBox(4096, "写入测试文件名", $testFile)
	FileWrite($file, $testFile & @CRLF)
	FileClose($file)
	
EndFunc


;;执行全部脚本分配在每台设备上
Func startAllTest2AllDevice()
	MsgBox(4096, "allTestStart", gettestFile() & "++" & $readDevice)
	Dim $allFiles = StringSplit(gettestFile(), "|")  
	Dim $readDeviceArr = StringSplit($readDevice, "|")
	
	For $f=1 To $allFiles[0] Step +1
		Dim $oneFile = $allFiles[$f]
		if $oneFile == "" Then ContinueLoop
		Dim $currentFileisRun = 1
		Sleep(1000)
		;MsgBox(4096, "oneFile", $oneFile)
		
		;不停的循环3个设备知道有空出的设备，依据shell ps | findstr com.alibaba命令查询进程是否存在
		while $currentFileisRun
			For $i=2 To $readDeviceArr[0] Step +1
				Dim $oneDev = $readDeviceArr[$i];
				;MsgBox(4096, $oneDev, $oneFile)	
				
				; 这里通过更目录下的设备名文件判断设备是否可用
				Local $file = FileOpen($oneDev, 0)
				If $file = -1 Then
					MsgBox(4096, "startAllTest2AllDevice错误1", "不能打开文件$oneDev" & $oneDev)
					ContinueLoop
				EndIf
				Local $devIsUse = FileRead($file, 1)
				FileClose($file)
				;MsgBox(4096, $oneDev, "命令返回:"&$devIsUse)
				Sleep(500)
				
				;只有设备没有被占用才可以执行脚本
				if $devIsUse == 0 Then
					;注册设备文件为 1，占用状态
					Local $file = FileOpen($oneDev, 2)
					If $file = -1 Then
						MsgBox(4096, "startAllTest2AllDevice错误2", "不能打开文件$oneDev-" & $oneDev)
						Exit
					EndIf
					FileWrite($file, "1" & @CRLF)
					FileClose($file)

					;MsgBox(4096, $oneDev, $oneFile & " 可以执行")
					;adb -s 11748585 shell am start -n com.alibaba.android.rimet/com.alibaba.android.rimet.biz.LaunchHomeActivity
					;Dim $commRun = "adb -s "&$oneDev&" shell am start -n com.alibaba.android.rimet/com.alibaba.android.rimet.biz.LaunchHomeActivity"
					
					;执行一台设备
					Dim $logFile = StringLeft($oneFile, StringLen($oneFile)-4)
					Dim $commRun = "python -m airtest run " & $rootDir & $oneFile & " --device android://127.0.0.1:5037/" & $oneDev
					$commRun = $commRun & " --log " & $rootDir & "logPic\" & $today & "\\" & $logFile & "_" & $oneDev
					;MsgBox(4096, $oneDev, $commRun)
					Run(@ComSpec & " /c "&$commRun, @SystemDir, @SW_HIDE, $STDOUT_CHILD)
					$currentFileisRun = 0
					;MsgBox(4096, "currentFileisRun", $currentFileisRun)
					Sleep(1000)
					;将记录写入logList中等待生成html日志
					save2LogList($today & "_" & $logFile & "_" & $oneDev)
					Sleep(1000)
					ExitLoop
				EndIf
				
			Next
			;Sleep(1500)
		Wend
	Next

	MsgBox(4096, "完成", "全部脚本执行完毕")
	;MsgBox(4096, "全部执行", $allFiles)
EndFunc



;;启动脚本
;;;airtest run E:\AirtestWorkSpace\koufu\sceneDingdongmaicai.air --device android://127.0.0.1:5037/HJS5T18A13016510 --log "E:\AirtestWorkSpace\koufu\logPic\6fe87b11ca1fc75ebe670439f20fabfc"
;; StringLen("How long am I?")  StringLeft("I am a string", 3)
Func startDevice($deviceInfo, $testFile)
	;MsgBox(4096,"",$deviceInfo &" ++ " &$testFile)
	Dim $logFile = StringLeft($testFile, StringLen($testFile)-4)
	if StringInStr($deviceInfo, "|") == 0 Then
		;执行一台设备
		Dim $comm1 = "python -m airtest run " & $rootDir & $testFile & " --device android://127.0.0.1:5037/" & $deviceInfo
		$comm1 = $comm1 & " --log " & $rootDir & "logPic\" & $today & "\" & $logFile & "_" & $deviceInfo
		MsgBox(4096,"",$comm1)
		Run(@ComSpec & " /c "&$comm1, @SystemDir, @SW_HIDE, $STDOUT_CHILD)
		Sleep(500)
		save2LogList($today & "_" & $logFile & "_" & $deviceInfo)
	Else
		;执行多台设备
		Dim $readDeviceArr = StringSplit($deviceInfo, "|")
		;For $oneDevice In $readDeviceArr
		For $i=2 To $readDeviceArr[0] Step +1
			Dim $comm1 = "python -m airtest run " & $rootDir & $testFile & " --device android://127.0.0.1:5037/" & $readDeviceArr[$i]
			$comm1 = $comm1 & " --log " & $rootDir & "logPic\" & $today & "\" & $logFile & "_" & $readDeviceArr[$i]
			;MsgBox(4096,"",$comm1)
			Run(@ComSpec & " /c "&$comm1, @SystemDir, @SW_HIDE, $STDOUT_CHILD)
			Sleep(500)
			save2LogList($today & "_" & $logFile & "_" & $readDeviceArr[$i])
		Next
	EndIf
	
	;return $PID
EndFunc



;添加设备到pidList中
;$pidList[$i][0] 设备名称
;$pidList[$i][1] pid
;$pidList[$i][2] 设备的完整名称 devices -l
;$pidList[$i][3] 设备启动参数
;;retuen 0 意味着数组都满了无法启动
Func addPidList($deviceName, $pid, $deviceInfo, $goodsName, $startime, $fromTo)
	if $deviceName == "" Then
		MsgBox(4096, "", "没有设备被选中")
		return 0
	EndIf

	;;第一次值插入 deviceName
	if $pid == "" Then
		;;第一循环验证是否有相同设备在运行
		For $i=0 To $size-1 Step +1
			if $pidList[$i][0] == $deviceName Then 
				MsgBox(4096, "", $deviceName&":正在运行")
				return 0
			EndIf
		Next
		;;第二次找到空位并插入
		For $i=0 To $size-1 Step +1
			if $pidList[$i][0] == "" Then 
				$pidList[$i][0] = $deviceName
				return 1
			EndIf
		Next
		;;如果没有空位就返回0
		MsgBox(4096, "提示", "最大支持设备数量:"&$size)
		return 0
	EndIf
	
	;;第二次根据deviceName插入或更新pid
	For $i=0 To $size-1 Step +1
		if $pidList[$i][0] == $deviceName Then 
			$pidList[$i][1] = $pid
			$pidList[$i][2] = $deviceInfo
			$pidList[$i][3] = $goodsName
			$pidList[$i][4] = $startime
			$pidList[$i][5] = $fromTo
			return 1
		EndIf
	Next
EndFunc

;读取测试文件
Func gettestFile()
	Local $hSearch = FileFindFirstFile("*.air")
	Local $testFiles

	; 检查搜索是否成功
	If $hSearch = -1 Then
		MsgBox(4096, "gettestFile", "没有文件/目录 匹配搜索")
		Exit
	EndIf

	While 1
		Local $sFile = FileFindNextFile($hSearch)
		If @error Then ExitLoop
		If $sFile == "common.air" Then ContinueLoop
		$testFiles = $testFiles & $sFile & "|"
		
	WEnd
	
	; 关闭搜索句柄
	FileClose($hSearch)
	
	Return $testFiles
EndFunc

;从设备列表中分离出pid
Func getDevicePid($deviceinfo)
	Dim $arr = StringSplit($deviceInfo, "       ")
	return $arr[1];
EndFunc

;读取输入框中的数据, $input是按钮的返回
Func getInput($input)
	Dim $r = GUICtrlRead($input)
	If $r == "" Then return ""
	If StringIsInt($r) == 1 Then
		return $r
	Else
		MsgBox(4096, "输入框验证", "不是数字")
		return ""
	EndIf
EndFunc

;初始化方法，检查logPic目录下是否有当日的文件夹
;检查web\airTestLog这个生成html目录下有没有当日文件夹
Func init()
	DirCreate("logPic\" & $today)
	DirCreate($export & $today)
EndFunc
